﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Noris.Schedule.Support;

namespace Noris.Tools.FrxEditor.Data
{
    /// <summary>
    /// Třída podporující práci na pozadí (Background)
    /// </summary>
    public class WorkingThread
    {
        #region Singleton
        private WorkingThread()
        {
            this._WaitForRequest = new AutoResetEvent(false);
            this._WorkThread = new Thread(this._BackgroundThreadRun);
            this._WorkThread.IsBackground = true;
            this._WorkThread.Name = "WorkingThread";
            this._WorkItems = new Queue<WorkItemData>();
        }
        private static WorkingThread Current
        {
            get
            {
                if (_Instance == null)
                {
                    lock (_Locker)
                    {
                        if (_Instance == null)
                        {
                            WorkingThread instance = new WorkingThread();
                            instance._WorkThread.Start();
                            _Instance = instance;
                        }
                    }
                }
                return _Instance;
            }
        }
        private static object _Locker = new object();
        private static WorkingThread _Instance;
        private Thread _WorkThread;
        #endregion
        #region Public static metody
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRun"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action actionRun, Action actionDone)
        {
            Current._AddItem(new WorkItemData(actionRun, null, null, ProgressFormMode.None, null, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRun"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action actionRun, Action<Exception> actionError, Action actionDone)
        {
            Current._AddItem(new WorkItemData(actionRun, null, null, ProgressFormMode.None, actionError, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRun"></param>
        /// <param name="actionProgress"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action actionRun, Action<WorkingThreadProgressArgs> actionProgress, Action actionDone)
        {
            Current._AddItem(new WorkItemData(actionRun, null, actionProgress, ProgressFormMode.None, null, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRun"></param>
        /// <param name="actionProgress"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action actionRun, Action<WorkingThreadProgressArgs> actionProgress, Action<Exception> actionError, Action actionDone)
        {
            Current._AddItem(new WorkItemData(actionRun, null, actionProgress, ProgressFormMode.None, actionError, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRun"></param>
        /// <param name="progressMode"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action actionRun, ProgressFormMode progressMode, Action actionDone)
        {
            Current._AddItem(new WorkItemData(actionRun, null, null, progressMode, null, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRun"></param>
        /// <param name="progressMode"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action actionRun, ProgressFormMode progressMode, Action<Exception> actionError, Action actionDone)
        {
            Current._AddItem(new WorkItemData(actionRun, null, null, progressMode, actionError, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action actionDone)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, ProgressFormMode.None, null, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action<Exception> actionError, Action actionDone)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, ProgressFormMode.None, actionError, actionDone, null, data));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionProgress"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action<WorkingThreadProgressArgs> actionProgress, Action actionDone)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, actionProgress, ProgressFormMode.None, null, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionProgress"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action<WorkingThreadProgressArgs> actionProgress, Action<Exception> actionError, Action actionDone)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, actionProgress, ProgressFormMode.None, actionError, actionDone, null, data));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="progressMode"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, ProgressFormMode progressMode, Action actionDone)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, progressMode, null, actionDone, null, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="progressMode"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDone"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, ProgressFormMode progressMode, Action<Exception> actionError, Action actionDone)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, progressMode, actionError, actionDone, null, data));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionDoneParam"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action<WorkingThreadDoneArgs> actionDoneParam)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, ProgressFormMode.None, null, null, actionDoneParam, data));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDoneParam"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action<Exception> actionError, Action<WorkingThreadDoneArgs> actionDoneParam)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, ProgressFormMode.None, actionError, null, actionDoneParam, null));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionProgress"></param>
        /// <param name="actionDoneParam"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action<WorkingThreadProgressArgs> actionProgress, Action<WorkingThreadDoneArgs> actionDoneParam)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, actionProgress, ProgressFormMode.None, null, null, actionDoneParam, data));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="actionProgress"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDoneParam"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, Action<WorkingThreadProgressArgs> actionProgress, Action<Exception> actionError, Action<WorkingThreadDoneArgs> actionDoneParam)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, actionProgress, ProgressFormMode.None, actionError, null, actionDoneParam, data));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="progressMode"></param>
        /// <param name="actionDoneParam"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, ProgressFormMode progressMode, Action<WorkingThreadDoneArgs> actionDoneParam)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, progressMode, null, null, actionDoneParam, data));
        }
        /// <summary>
        /// Přidá další požadavek na akci na pozadí
        /// </summary>
        /// <param name="actionRunParam"></param>
        /// <param name="data"></param>
        /// <param name="progressMode"></param>
        /// <param name="actionError"></param>
        /// <param name="actionDoneParam"></param>
        public static void AddItem(Action<WorkingThreadArgs> actionRunParam, object data, ProgressFormMode progressMode, Action<Exception> actionError, Action<WorkingThreadDoneArgs> actionDoneParam)
        {
            Current._AddItem(new WorkItemData(null, actionRunParam, null, progressMode, actionError, null, actionDoneParam, data));
        }
        /// <summary>
        /// Tuto metodu volá výkonná metoda běžící na pozadí.
        /// Řídící vrstva WorkingThread zajistí předání dat (progress) do té metody, která byla zadána při definování úkolu.
        /// </summary>
        /// <param name="progress"></param>
        public static void DoProgress(ProgressData progress)
        {
            Current._DoProgress(progress);
        }
        /// <summary>
        /// Ukončí výkon celého systému Background.
        /// Volá se při ukončení aplikace.
        /// </summary>
        public static void Close()
        {
            Current._Close();
        }
        #endregion
        #region Private instanční metody
        private void _AddItem(WorkItemData item)
        {
            item.CallerThread = Thread.CurrentThread;  // Do požadavku si uložím thread, který jej vyvolal.
            item.PrepareProgressForm();                // Do požadavku si připravíme Form, který reprezentuje Progress
            lock (this._WorkItems)
            {
                this._WorkItems.Enqueue(item);
            }
            this._WaitForRequest.Set();                // Zazvoníme na zvoneček, že přišla nová položka práce
        }
        private void _DoProgress(ProgressData progress)
        {
            WorkItemData workItem = this._CurrentItem;
            if (workItem != null)
                workItem.DoProgress(progress);
        }
        private void _Close()
        {
            lock (this._WorkItems)
            {
                this._WorkItems.Clear();
            }
            this._WorkThread.Abort();
        }
        #endregion
        #region Thread on background
        /// <summary>
        /// V této metodě stráví thread na pozadí svůj aktivní život (když se něco děje).
        /// </summary>
        private void _BackgroundThreadRun()
        {
            while (true)
            {
                WorkItemData workItem = this._BackgroundGetNext();
                if (workItem != null)
                {
                    try
                    {
                        this._CurrentItem = workItem;
                        workItem.Run();
                    }
                    catch (Exception exc)
                    {
                        workItem.Exc = exc;
                    }
                    finally
                    {
                        workItem.Done();
                        this._CurrentItem = null;
                    }
                }
            }
        }
        /// <summary>
        /// Aktuálně běžící aktivita na pozadí, vždy je jen jedna (tento objekt nepodporuje pravý multithreading).
        /// Je nastaveno před spuštěním akce Run, a je nullováno po dokončení akce Done.
        /// </summary>
        private WorkItemData _CurrentItem;
        /// <summary>
        /// V této metodě stráví thread na pozadí svůj pasivní život (když se čeká na to, až se bude něco dít).
        /// </summary>
        /// <returns></returns>
        private WorkItemData _BackgroundGetNext()
        {
            while (true)
            {
                this._WaitForRequest.Reset();          // Pokud někdo zvonil na zvoneček, tak zvoneček utišíme.
                lock (this._WorkItems)
                {
                    if (this._WorkItems.Count > 0)
                    {
                        WorkItemData item = this._WorkItems.Dequeue();
                        return item;
                    }
                }
                this._WaitForRequest.WaitOne();        // Aktivujeme zvoneček a jdeme spát, dokud nám nezazvoní.
            }
        }
        /// <summary>
        /// Zvoneček = signalizační zařízení, které umožní vláknu na pozadí "spát", když nemá co dělat.
        /// </summary>
        private AutoResetEvent _WaitForRequest;
        /// <summary>
        /// Seznam položek práce
        /// </summary>
        private Queue<WorkItemData> _WorkItems;
        #endregion
        #region class WorkItemData : soukromá položka práce na pozadí
        /// <summary>
        /// WorkItemData : soukromá položka práce na pozadí.
        /// Obsahuje zachycené parametry definující jednotku práce na pozadí = jednu akci.
        /// </summary>
        protected class WorkItemData
        {
            internal WorkItemData(Action actionRun, Action<WorkingThreadArgs> actionRunParam, Action<WorkingThreadProgressArgs> actionProgress, ProgressFormMode progressMode, Action<Exception> actionError, Action actionDone, Action<WorkingThreadDoneArgs> actionDoneParam, object data)
            {
                this.ActionRun = actionRun;
                this.ActionRunParam = actionRunParam;
                this.ActionProgress = actionProgress;
                this.ProgressMode = progressMode;
                this.ActionError = actionError;
                this.ActionDone = actionDone;
                this.ActionDoneParam = actionDoneParam;
                this.Data = data;
            }
            /// <summary>
            /// Thread volajícího.
            /// Třeba jednou budeme umět invokovat do tohoto threadu událost Done.
            /// </summary>
            internal Thread CallerThread;
            /// <summary>
            /// Akce Run (bezparametrická) = spouští se, když na tuto akci přijde řada ve frontě
            /// </summary>
            internal Action ActionRun;
            /// <summary>
            /// Akce Run (s parametrem) = spouští se, když na tuto akci přijde řada ve frontě
            /// </summary>
            internal Action<WorkingThreadArgs> ActionRunParam;
            /// <summary>
            /// Akce, která zobrazuje uživateli progres v metodě na pozadí
            /// </summary>
            internal Action<WorkingThreadProgressArgs> ActionProgress;
            /// <summary>
            /// Režim okna Progress
            /// </summary>
            internal ProgressFormMode ProgressMode;
            /// <summary>
            /// Akce, která je vyvolána v případě chyby, která se stala ve výkonné metodě.
            /// </summary>
            internal Action<Exception> ActionError;
            /// <summary>
            /// Akce Done (bezparametrická) = spouští se, když doběhne výkonná metoda na pozadí
            /// </summary>
            internal Action ActionDone;
            /// <summary>
            /// Akce Done (s parametrem) = spouští se, když doběhne výkonná metoda na pozadí
            /// </summary>
            internal Action<WorkingThreadDoneArgs> ActionDoneParam;
            /// <summary>
            /// Úložiště objektu s daty, který se předává do výkonné metody ActionRun (metoda s parametrem)
            /// </summary>
            internal object Data;
            /// <summary>
            /// Zachycená výjimka
            /// </summary>
            internal Exception Exc;
            /// <summary>
            /// Vstupní bod výkonné metody.
            /// Spouští se v threadu na pozadí.
            /// Řeší se zde volba akce ActionRun() / ActionRunParam(Data)
            /// </summary>
            internal void Run()
            {
                if (this.ActionRun != null)
                    this.ActionRun();
                else if (this.ActionRunParam != null)
                    this.ActionRunParam(new WorkingThreadArgs(this.Data));
            }
            /// <summary>
            /// Vstupní bod progresu.
            /// </summary>
            /// <param name="progress"></param>
            internal void DoProgress(ProgressData progress)
            {
                if (this.ActionProgress != null)
                    this.ActionProgress(new WorkingThreadProgressArgs(this.Data, progress));
                if (this._ProgressForm != null)
                    this.ActionProgressOnForm(progress);
            }
            /// <summary>
            /// Vstupní bod pro volání metody Done, po doběhnutí metody Run.
            /// </summary>
            internal void Done()
            {
                this.DeactivateProgressForm();

                if (this.Exc != null && this.ActionError != null)
                    this.ActionError(this.Exc);
                else if (this.ActionDone != null)
                    this.ActionDone();
                else if (this.ActionDoneParam != null)
                    this.ActionDoneParam(new WorkingThreadDoneArgs(this.Data, this.Exc));
            }
            /// <summary>
            /// Připraví objekt formuláře
            /// </summary>
            internal void PrepareProgressForm()
            {
                if (this.ProgressMode == ProgressFormMode.ShowNoCancel || this.ProgressMode == ProgressFormMode.ShowWithCancel)
                {
                    this._ProgressForm = new ProgressForm();
                    this._ProgressForm.Data = new ProgressData() { CancelVisible = (this.ProgressMode == ProgressFormMode.ShowWithCancel) };
                }
            }
            /// <summary>
            /// Předá data o progresu do formuláře
            /// </summary>
            /// <param name="progress"></param>
            private void ActionProgressOnForm(ProgressData progress)
            {
                if (this._ProgressForm == null) return;
                if (!this._ProgressFormShowed)
                {
                    Steward.ShowFormInGuiThread(this._ProgressForm);
                    this._ProgressFormShowed = true;
                }
                this._ProgressForm.Data = progress;
                if (this._ProgressForm.Data.CancelProcess)
                    progress.CancelProcess = true;
            }

            private void DeactivateProgressForm()
            {
                if (this._ProgressForm == null) return;

                if (this._ProgressForm.InvokeRequired)
                    this._ProgressForm.BeginInvoke(new Action(this.DeactivateProgressForm));
                else
                {
                    this._ProgressForm.Hide();
                    this._ProgressForm.Close();
                    this._ProgressForm.Dispose();
                    this._ProgressForm = null;
                }
            }

            internal ProgressForm _ProgressForm;
            internal bool _ProgressFormShowed;
        }
        #endregion
    }
    #region Třídy argumentů
    /// <summary>
    /// Třída argumentů pro předání dat o progresu
    /// </summary>
    public class WorkingThreadProgressArgs : WorkingThreadArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="data"></param>
        /// <param name="progressData"></param>
        public WorkingThreadProgressArgs(object data, ProgressData progressData)
            : base(data)
        {
            this.ProgressData = progressData;
        }
        /// <summary>
        /// Data o postupu
        /// </summary>
        public ProgressData ProgressData { get; private set; }
    }
    /// <summary>
    /// Třída argumentů pro převzetí výsledku po dokončení běhu metody na pozadí
    /// </summary>
    public class WorkingThreadDoneArgs : WorkingThreadArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="data"></param>
        /// <param name="exc"></param>
        public WorkingThreadDoneArgs(object data, Exception exc)
            : base(data)
        {
            this.Exc = exc;
        }
        /// <summary>
        /// Chyba, k níž došlo
        /// </summary>
        public Exception Exc { get; private set; }
    }
    /// <summary>
    /// Základní třída argumentů pro metody pracující na pozadí, obsahuje objekt s daty
    /// </summary>
    public class WorkingThreadArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="data"></param>
        public WorkingThreadArgs(object data)
        {
            this.Data = data;
        }
        /// <summary>
        /// Uživatelská data
        /// </summary>
        public object Data { get; private set; }
    }
    #endregion
    #region class ProgressData : Data do/z progress baru.
    /// <summary>
    /// ProgressData : Data do/z progress baru.
    /// Default hodnota každé datové property je null, což při setování má význam "Nesetovat odpovídající property".
    /// </summary>
    public class ProgressData
    {
        /// <summary>Má být viditelný text Caption = před progress barem?  Null hodnota (default) = neměnit aktuální stav</summary>
        public bool? ProgressCaptionVisible { get; set; }
        /// <summary>Text do políčka Caption.  Null hodnota (default) = neměnit aktuální stav</summary>
        public string ProgressCaptionText { get; set; }
        /// <summary>Má být viditelný Progress bar?  Null hodnota (default) = neměnit aktuální stav</summary>
        public bool? ProgressBarVisible { get; set; }
        /// <summary>Hodnota do ProgressBaru, v rozmezí 0 až 1.  Null hodnota (default) = neměnit aktuální stav</summary>
        public float? ProgressBarRatio { get; set; }
        /// <summary>Má být viditelný text Count = za progress barem? Text je určen pro zobrazení počtu.  Null hodnota (default) = neměnit aktuální stav</summary>
        public bool? ProgressCountVisible { get; set; }
        /// <summary>Text do políčka Count. Text je určen pro zobrazení počtu.  Null hodnota (default) = neměnit aktuální stav</summary>
        public string ProgressCountText { get; set; }
        /// <summary>Má být viditelný text Error = za textem Count? Text je určen pro zobrazení chyb.  Null hodnota (default) = neměnit aktuální stav</summary>
        public bool? ProgressErrorVisible { get; set; }
        /// <summary>Text do políčka Error. Text je určen pro zobrazení chyb.  Null hodnota (default) = neměnit aktuální stav</summary>
        public string ProgressErrorText { get; set; }
        /// <summary>Příznak viditelnosti buttonu Cancel</summary>
        public bool? CancelVisible { get; set; }
        /// <summary>Příznak Cancel, nastavený z UI do procesu</summary>
        public bool CancelProcess { get; set; }
    }
    #endregion
    #region class ProgressPanel : panel, který zobrazuje data z ProgressData
    /// <summary>
    /// ProgressPanel : panel, který zobrazuje data z ProgressData
    /// </summary>
    public class ProgressPanel : Components.DPanel
    {
        #region Konstrukce
        /// <summary>
        /// ProgressPanel : panel, který zobrazuje data z ProgressData.
        /// </summary>
        public ProgressPanel()
        {
            this.InitComponents();
        }
        private void InitComponents()
        {
            this.CaptionLabel = new System.Windows.Forms.Label();
            this.Progress = new System.Windows.Forms.ProgressBar();
            this.ProgressLabel = new System.Windows.Forms.Label();
            this.ErrorLabel = new System.Windows.Forms.Label();
            this.CancelButton = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // ProgressPanel
            // 
            this.Controls.Add(this.CancelButton);
            this.Controls.Add(this.ErrorLabel);
            this.Controls.Add(this.Progress);
            this.Controls.Add(this.CaptionLabel);
            this.Controls.Add(this.ProgressLabel);
            this.Dock = System.Windows.Forms.DockStyle.Fill;
            this.Location = new System.Drawing.Point(0, 0);
            this.MinimumSize = new System.Drawing.Size(362, 114);
            this.Name = "ProgressPanel";
            this.Size = new System.Drawing.Size(364, 117);
            this.TabIndex = 0;
            // 
            // CaptionLabel
            // 
            this.CaptionLabel.AutoSize = true;
            this.CaptionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
            this.CaptionLabel.Location = new System.Drawing.Point(29, 7);
            this.CaptionLabel.Name = "CaptionLabel";
            this.CaptionLabel.Size = new System.Drawing.Size(63, 17);
            this.CaptionLabel.TabIndex = 0;
            this.CaptionLabel.Text = "Caption";
            // 
            // Progress
            // 
            this.Progress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
            | System.Windows.Forms.AnchorStyles.Right)));
            this.Progress.Location = new System.Drawing.Point(14, 43);
            this.Progress.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
            this.Progress.Minimum = 0;
            this.Progress.Maximum = 1000;
            this.Progress.Value = 0;
            this.Progress.Name = "Progress";
            this.Progress.Size = new System.Drawing.Size(336, 20);
            this.Progress.TabIndex = 1;
            // 
            // LabelProgress
            // 
            this.ProgressLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
            | System.Windows.Forms.AnchorStyles.Right)));
            this.ProgressLabel.Location = new System.Drawing.Point(19, 27);
            this.ProgressLabel.Name = "ProgressLabel";
            this.ProgressLabel.Size = new System.Drawing.Size(327, 23);
            this.ProgressLabel.TabIndex = 2;
            this.ProgressLabel.Text = "";
            this.ProgressLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter;
            // 
            // ErrorLabel
            // 
            this.ErrorLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
            | System.Windows.Forms.AnchorStyles.Left)
            | System.Windows.Forms.AnchorStyles.Right)));
            this.ErrorLabel.Location = new System.Drawing.Point(19, 72);
            this.ErrorLabel.Name = "ErrorLabel";
            this.ErrorLabel.Size = new System.Drawing.Size(221, 34);
            this.ErrorLabel.TabIndex = 3;
            this.ErrorLabel.Text = "";
            // 
            // CancelButton
            // 
            this.CancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.CancelButton.Location = new System.Drawing.Point(246, 76);
            this.CancelButton.Name = "CancelButton";
            this.CancelButton.Size = new System.Drawing.Size(89, 30);
            this.CancelButton.TabIndex = 4;
            this.CancelButton.Text = "Cancel";
            this.CancelButton.UseVisualStyleBackColor = true;
            this.CancelButton.Click += new EventHandler(CancelButton_Click);

            // Panel:
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        void CancelButton_Click(object sender, EventArgs e)
        {
            this.Canceled = true;
            this.CancelButton.Text = "Canceled...";
            this.CancelButton.Enabled = false;
        }
        private System.Windows.Forms.Button CancelButton;
        private System.Windows.Forms.Label ErrorLabel;
        private System.Windows.Forms.Label ProgressLabel;
        private System.Windows.Forms.ProgressBar Progress;
        private System.Windows.Forms.Label CaptionLabel;
        private bool Canceled;
        #endregion
        #region Property s daty
        /// <summary>
        /// Data o progresu
        /// </summary>
        public ProgressData Data
        {
            get
            {
                if (this.InvokeRequired)
                    return (ProgressData)this.Invoke(new Func<ProgressData>(this._GetData));
                return this._GetData();
            }
            set
            {
                if (this.InvokeRequired)
                    this.BeginInvoke(new Action<ProgressData>(this._SetData), value);
            }
        }
        private ProgressData _GetData()
        {
            ProgressData data = new ProgressData()
            {
                ProgressCaptionVisible = this.CaptionLabel.Visible,
                ProgressCaptionText = this.CaptionLabel.Text,
                ProgressBarVisible = this.Progress.Visible,
                ProgressBarRatio = this._GetProgressRatio(),
                ProgressCountVisible = this.ProgressLabel.Visible,
                ProgressCountText = this.ProgressLabel.Text,
                ProgressErrorVisible = this.ErrorLabel.Visible,
                ProgressErrorText = this.ErrorLabel.Text,
                CancelVisible = this.CancelButton.Visible,
                CancelProcess = this.Canceled
            };
            return data;
        }
        private void _SetData(ProgressData data)
        {
            if (data.ProgressCaptionVisible.HasValue) this.CaptionLabel.Visible = data.ProgressCaptionVisible.Value;
            if (data.ProgressCaptionText != null) this.CaptionLabel.Text = data.ProgressCaptionText;
            if (data.ProgressBarVisible.HasValue) this.Progress.Visible = data.ProgressBarVisible.Value;
            if (data.ProgressBarRatio.HasValue) this._GetProgressRatio(data.ProgressBarRatio.Value);
            if (data.ProgressCountVisible.HasValue) this.ProgressLabel.Visible = data.ProgressCountVisible.Value;
            if (data.ProgressCountText != null) this.ProgressLabel.Text = data.ProgressCountText;
            if (data.ProgressErrorVisible.HasValue) this.ErrorLabel.Visible = data.ProgressErrorVisible.Value;
            if (data.ProgressErrorText != null) this.ErrorLabel.Text = data.ProgressErrorText;
            if (data.CancelVisible.HasValue) this.CancelButton.Visible = data.CancelVisible.Value;
        }
        private float? _GetProgressRatio()
        {
            if (!this.Progress.Visible) return null;
            return (float)(this.Progress.Value - this.Progress.Minimum) /
                   (float)(this.Progress.Maximum - this.Progress.Minimum);
        }
        private void _GetProgressRatio(float ratio)
        {
            this.Progress.Value = (int)Math.Round(((float)(this.Progress.Maximum - this.Progress.Minimum) * ratio), 0) + this.Progress.Minimum;
        }
        #endregion
    }
    #endregion
    #region class ProgressForm : formulář připravený pro použití jako progress
    /// <summary>
    /// ProgressForm : formulář připravený pro použití jako progress
    /// </summary>
    public partial class ProgressForm : System.Windows.Forms.Form
    {
        #region Konstrukce
        /// <summary>
        /// ProgressForm : formulář připravený pro použití jako progress
        /// </summary>
        public ProgressForm()
        {
            InitializeComponent();
        }
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        private ProgressPanel ProgressPanel;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #endregion
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.ProgressPanel = new ProgressPanel();
            this.SuspendLayout();
            // 
            // ProgressPanel
            // 
            this.ProgressPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.ProgressPanel.Location = new System.Drawing.Point(0, 0);
            this.ProgressPanel.MinimumSize = new System.Drawing.Size(362, 114);
            this.ProgressPanel.Name = "ProgressPanel";
            this.ProgressPanel.Size = new System.Drawing.Size(364, 117);
            this.ProgressPanel.TabIndex = 0;
            // 
            // ProgressForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ControlBox = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            this.ClientSize = new System.Drawing.Size(364, 117);
            this.Controls.Add(this.ProgressPanel);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
            this.MinimumSize = new System.Drawing.Size(372, 143);
            this.Name = "ProgressForm";
            this.Text = "Progress";
            this.ResumeLayout(false);

        }
        #endregion
        #region Property s daty
        /// <summary>
        /// Data o progresu
        /// </summary>
        public ProgressData Data
        {
            get { return this.ProgressPanel.Data; }
            set { this.ProgressPanel.Data = value; }
        }
        #endregion
    }
    #endregion
    #region enum ProgressFormMode
    /// <summary>
    /// Režim okna Progress
    /// </summary>
    public enum ProgressFormMode
    {
        None,
        ShowNoCancel,
        ShowWithCancel
    }
    #endregion
}
